import { Router } from 'express';
import bcrypt from 'bcryptjs';
import cookieParser from 'cookie-parser';
import dayjs from 'dayjs';
import multer from 'multer';
import path from 'path';
import fs from 'fs';
import { prisma } from '@src/common/database';
import Paths from '@src/common/constants/Paths';
import { jsonResponse } from '@src/common/util/bigint-serializer';

const router = Router();
router.use(cookieParser());

// helpers
const SESSION_COOKIE = 'sid';
const DEFAULT_TTL_HOURS = 24; // 1天
const REMEMBER_TTL_DAYS = 30; // 30天

function getExpire(rem: boolean) {
  return rem ? dayjs().add(REMEMBER_TTL_DAYS, 'day').toDate() : dayjs().add(DEFAULT_TTL_HOURS, 'hour').toDate();
}

// 配置 multer 存储（用户头像）
const avatarStorage = multer.diskStorage({
  destination: (_req, _file, cb) => {
    const uploadPath = path.join(__dirname, '../../uploads/avatars');
    if (!fs.existsSync(uploadPath)) {
      fs.mkdirSync(uploadPath, { recursive: true });
    }
    cb(null, uploadPath);
  },
  filename: (_req, file, cb) => {
    const timestamp = Date.now();
    const ext = path.extname(file.originalname).toLowerCase();
    const name = `${timestamp}-${Math.random().toString(36).substring(2)}${ext}`;
    cb(null, name);
  }
});

const avatarUpload = multer({
  storage: avatarStorage,
  limits: { fileSize: 5 * 1024 * 1024 }, // 5MB
  fileFilter: (_req, file, cb) => {
    const allowed = ['.jpg', '.jpeg', '.png', '.webp'];
    const ext = path.extname(file.originalname).toLowerCase();
    if (allowed.includes(ext)) return cb(null, true);
    cb(new Error('jpg, jpeg, png, webp 형식의 프로필 사진만 지원됩니다'));
  }
});

// POST /api/auth/register
router.post(Paths.Auth.Register, async (req, res) => {
  try {
    const { login_id, email, password, name, nickname, phone, gender, birthdate, partner_code } = req.body ?? {};

    if (!login_id || !email || !password || !partner_code) {
      return res.status(400).json({ error: 'login_id, email, password, partner_code는 필수입니다' });
    }

    // 验证推荐码格式（6-10位大写字母和数字）
    if (!/^[A-Z0-9]{6,10}$/.test(partner_code)) {
      return res.status(400).json({ error: '추천 코드 형식이 올바르지 않습니다. 6-10자 대문자와 숫자여야 합니다' });
    }

    const [existsLogin, existsEmail, existsPhone, partnerProfile] = await Promise.all([
      prisma.user.findUnique({ where: { loginId: login_id }, select: { id: true } }),
      prisma.user.findUnique({ where: { email }, select: { id: true } }),
      phone ? prisma.user.findUnique({ where: { phone }, select: { id: true } }) : Promise.resolve(null),
      prisma.partnerProfile.findUnique({
        where: { referralCode: partner_code },
        include: {
          user: {
            select: { id: true, role: true, status: true }
          }
        }
      }),
    ]);

    if (existsLogin) return res.status(409).json({ error: 'login_id가 이미 존재합니다' });
    if (existsEmail) return res.status(409).json({ error: 'email이 이미 존재합니다' });
    if (existsPhone) return res.status(409).json({ error: 'phone이 이미 존재합니다' });

    if (!partnerProfile) {
      return res.status(400).json({ error: '추천 코드가 존재하지 않습니다' });
    }

    if (!partnerProfile.isActive) {
      return res.status(400).json({ error: '추천 코드가 비활성화되었습니다' });
    }

    if (partnerProfile.user.status !== 'active') {
      return res.status(400).json({ error: '추천인 계정이 비활성화되었습니다' });
    }

    // 支持合作伙伴和管理员的推荐码
    if (partnerProfile.user.role !== 'partner' && partnerProfile.user.role !== 'admin') {
      return res.status(400).json({ error: '유효하지 않은 추천 코드입니다' });
    }

    const passwordHash = await bcrypt.hash(password, 10);

    const user = await prisma.user.create({
      data: {
        loginId: login_id,
        email,
        passwordHash,
        name,
        nickname,
        phone,
        gender,
        birthdate: birthdate ? new Date(birthdate) : undefined,
        referrerId: partnerProfile.user.id,
      },
    });

    // ensure wallet exists
    await prisma.userWallet.upsert({ where: { userId: user.id }, update: {}, create: { userId: user.id, pointsBalance: BigInt(0) } });

    return res.status(201).json({ id: String(user.id), login_id: user.loginId, email: user.email });
  } catch (err) {
    console.error(err);
    return res.status(500).json({ error: '회원가입 실패' });
  }
});

// POST /api/auth/login
router.post(Paths.Auth.Login, async (req, res) => {
  try {
    const { identifier, password, rememberMe } = req.body ?? {};
    if (!identifier || !password) {
      return res.status(400).json({ error: 'identifier, password는 필수입니다' });
    }

    const user = await prisma.user.findFirst({
      where: {
        OR: [
          { loginId: identifier },
          { email: identifier },
        ],
      },
    });
    if (!user) return res.status(401).json({ error: '아이디 또는 비밀번호가 잘못되었습니다' });

    const ok = await bcrypt.compare(password, user.passwordHash);
    if (!ok) return res.status(401).json({ error: '아이디 또는 비밀번호가 잘못되었습니다' });

    const expiredAt = getExpire(!!rememberMe);
    const session = await prisma.userSession.create({
      data: {
        userId: user.id,
        expiredAt,
      },
    });

    res.cookie(SESSION_COOKIE, String(session.id), {
      httpOnly: true,
      sameSite: 'lax',
      secure: false,
      expires: expiredAt,
      path: '/',
    });

    return res.json({ id: String(user.id), login_id: user.loginId, email: user.email });
  } catch (err) {
    console.error(err);
    return res.status(500).json({ error: '로그인 실패' });
  }
});

// POST /api/auth/logout
router.post(Paths.Auth.Logout, async (req, res) => {
  try {
    const sid = req.cookies?.[SESSION_COOKIE];
    if (sid) {
      await prisma.userSession.delete({ where: { id: BigInt(sid) } }).catch(() => {});
    }
    res.clearCookie(SESSION_COOKIE, { path: '/' });
    return res.json({ ok: true });
  } catch (err) {
    console.error(err);
    return res.status(500).json({ error: '로그아웃 실패' });
  }
});

// GET /api/auth/me
router.get(Paths.Auth.Me, async (req, res) => {
  try {
    const sid = req.cookies?.[SESSION_COOKIE];
    if (!sid) return res.status(401).json({ error: '로그인되지 않음' });
    const sess = await prisma.userSession.findUnique({ where: { id: BigInt(sid) } });
    if (!sess || new Date(sess.expiredAt) < new Date()) {
      return res.status(401).json({ error: '세션이 만료됨' });
    }
    const user = await prisma.user.findUnique({
      where: { id: sess.userId },
      select: {
        id: true,
        loginId: true,
        email: true,
        name: true,
        nickname: true,
        phone: true,
        gender: true,
        birthdate: true,
        avatarUrl: true,
        role: true,
        status: true,
        memberLevel: true,
        wallet: {
          select: {
            pointsBalance: true
          }
        }
      },
    });
    return jsonResponse(res, user ? {
      ...user,
      id: String(user.id),
      wallet: user.wallet ? {
        pointsBalance: String(user.wallet.pointsBalance)
      } : null
    } : null);
  } catch (err) {
    console.error(err);
    return res.status(500).json({ error: '조회 실패' });
  }
});


// POST /api/auth/me/avatar/upload - 用户上传头像文件（顶层注册）
router.post(Paths.Auth.Me + '/avatar/upload', avatarUpload.single('avatar'), async (req, res) => {
  try {
    const sid = req.cookies?.[SESSION_COOKIE]
    if (!sid) return res.status(401).json({ error: '로그인되지 않음' })
    const sess = await prisma.userSession.findUnique({ where: { id: BigInt(sid) } })
    if (!sess || new Date(sess.expiredAt) < new Date()) {
      return res.status(401).json({ error: '세션이 만료됨' })
    }
    const file = req.file as Express.Multer.File | undefined
    if (!file) return res.status(400).json({ error: '프로필 사진을 업로드해주세요 (필드명: avatar)' })
    const avatarUrl = `/files/avatars/${file.filename}`
    return res.json({ avatarUrl })
  } catch (err) {
    console.error('프로필 사진 업로드 실패:', err)
    return res.status(500).json({ error: '프로필 사진 업로드 실패' })
  }
})

// PUT /api/auth/profile - 更新个人资料
router.put(Paths.Auth.Me + '/profile', async (req, res) => {
  try {
    const sid = req.cookies?.[SESSION_COOKIE];
    if (!sid) return res.status(401).json({ error: '로그인되지 않음' });

    const sess = await prisma.userSession.findUnique({ where: { id: BigInt(sid) } });
    if (!sess || new Date(sess.expiredAt) < new Date()) {
      return res.status(401).json({ error: '세션이 만료됨' });
    }

    const { name, nickname, phone, gender, birthdate } = req.body ?? {};

    // 验证性别值
    if (gender !== undefined && !['male', 'female', 'other', null, ''].includes(gender)) {
      return res.status(400).json({ error: '성별 값이 유효하지 않습니다' });
    }

    // 移除휴대폰 번호 형식 검증 - 作为普通文本处理

    // 检查手机号是否已被其他用户使用
    if (phone) {
      const existingUser = await prisma.user.findFirst({
        where: {
          phone,
          id: { not: sess.userId }
        },
        select: { id: true }
      });
      if (existingUser) {
        return res.status(409).json({ error: '휴대폰 번호가 이미 사용 중입니다' });
      }
    }

    const data: any = {};
    if (name !== undefined) data.name = name === null || name === '' ? null : String(name);
    if (nickname !== undefined) data.nickname = nickname === null || nickname === '' ? null : String(nickname);
    if (phone !== undefined) data.phone = phone === null || phone === '' ? null : String(phone);
    if (gender !== undefined) data.gender = gender || null;
    if (birthdate !== undefined) {
      data.birthdate = birthdate ? new Date(birthdate) : null;
    }

    const updatedUser = await prisma.user.update({
      where: { id: sess.userId },
      data,
      select: {
        id: true,
        loginId: true,
        email: true,
        name: true,
        nickname: true,
        phone: true,
        gender: true,
        birthdate: true,
        avatarUrl: true,
        role: true,
        status: true
      },
    });

    return res.json({ ...updatedUser, id: String(updatedUser.id) });
  } catch (err) {
    console.error('개인정보 업데이트 실패:', err);
    return res.status(500).json({ error: '개인정보 업데이트 실패' });
  }
});

// PUT /api/auth/password - 修改密码
router.put(Paths.Auth.Me + '/password', async (req, res) => {
  try {
    const sid = req.cookies?.[SESSION_COOKIE];
    if (!sid) return res.status(401).json({ error: '로그인되지 않음' });

    const sess = await prisma.userSession.findUnique({ where: { id: BigInt(sid) } });
    if (!sess || new Date(sess.expiredAt) < new Date()) {
      return res.status(401).json({ error: '세션이 만료됨' });
    }

    const { currentPassword, newPassword } = req.body ?? {};

    if (!currentPassword || !newPassword) {
      return res.status(400).json({ error: '현재 비밀번호와 새 비밀번호는 필수입니다' });
    }

    if (newPassword.length < 8) {
      return res.status(400).json({ error: '새 비밀번호는 최소 8자 이상이어야 합니다' });
    }

    // 验证当前密码
    const user = await prisma.user.findUnique({
      where: { id: sess.userId },
      select: { passwordHash: true }
    });

    if (!user) {
      return res.status(404).json({ error: '사용자가 존재하지 않습니다' });
    }

    const isCurrentPasswordValid = await bcrypt.compare(currentPassword, user.passwordHash);
    if (!isCurrentPasswordValid) {
      return res.status(400).json({ error: '현재 비밀번호가 틀렸습니다' });
    }

    // 更新密码
    const newPasswordHash = await bcrypt.hash(newPassword, 10);
    await prisma.user.update({
      where: { id: sess.userId },
      data: { passwordHash: newPasswordHash },
    });

    return res.json({ success: true, message: '비밀번호 변경 성공' });
  } catch (err) {
    console.error('비밀번호 변경 실패:', err);
    return res.status(500).json({ error: '비밀번호 변경 실패' });
  }
});

// PUT /api/auth/avatar - 更新头像
router.put(Paths.Auth.Me + '/avatar', async (req, res) => {
  try {
    const sid = req.cookies?.[SESSION_COOKIE];
    if (!sid) return res.status(401).json({ error: '로그인되지 않음' });

    const sess = await prisma.userSession.findUnique({ where: { id: BigInt(sid) } });
    if (!sess || new Date(sess.expiredAt) < new Date()) {
      return res.status(401).json({ error: '세션이 만료됨' });
    }



    const { avatarUrl } = req.body ?? {};

    if (!avatarUrl) {
      return res.status(400).json({ error: '프로필 사진 URL은 필수입니다' });
    }

    const updatedUser = await prisma.user.update({
      where: { id: sess.userId },
      data: { avatarUrl },
      select: {
        id: true,
        loginId: true,
        email: true,
        name: true,
        nickname: true,
        phone: true,
        gender: true,
        birthdate: true,
        avatarUrl: true,
        role: true,
        status: true
      },
    });

    return res.json({ ...updatedUser, id: String(updatedUser.id) });
  } catch (err) {
    console.error('프로필 사진 업데이트 실패:', err);
    return res.status(500).json({ error: '프로필 사진 업데이트 실패' });
  }
});

export default router;

